//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <string.h>
#include "depend.h"
#include "board_protocol.h"

EXTERN DzMutex g_IOBriageMutex;
EXTERN DzEvent g_IOBriageEvent;
EXTERN UInt32 IOAddress;

UInt32 IO_GetFileAttributes(WString wcsName)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(GetFileAttributes)
    {
        WChar *pFileName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pFileName, wcsName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return reply->attr;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return IO_INVALID_FILE_ATTRIBUTES;
}

Boolean IO_SetFileAttributes(WString wcsName, UInt32 attr)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(SetFileAttributes)
    {
        WChar *pFileName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pFileName, wcsName);
        req->attr = attr;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_DeleteFile(WString wcsName)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(DeleteFile)
    {
        WChar *pFileName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pFileName, wcsName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_MoveFile(
                WString wcsOldName,
                WString wcsNewName)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(MoveFile)
    {
        WChar *pOldFileName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pOldFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pOldFileName, wcsOldName);
        //6144 = 4096 + 2048, new file name stores from here
        req->NewFileNameBuf = 6144;
        WChar *pNewFileName = (WChar *)((char *)req + req->NewFileNameBuf);
        wcscpy(pNewFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pNewFileName, wcsNewName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_CreateDirectory(
                WString wcsPathName)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );
    SERVER_START_REQ(CreateDirectory)
    {
        WChar *pPathName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pPathName, L".\\D\\");            //Add the real path prefix
        wcscat(pPathName, wcsPathName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_RemoveDirectory(
                WString wcsPathName)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(RemoveDirectory)
    {
        WChar *pPathName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pPathName, L".\\D\\");            //Add the real path prefix
        wcscat(pPathName, wcsPathName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

PVoid IO_CreateFile(
                WString wcsFileName,
                UInt32 ulDesiredAccess,
                UInt32 ulShareMode,
                UInt32 ulCreationDisposition,
                UInt32 ulFlagsAndAttributes,
                PVoid hTemplateFile)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(CreateFile)
    {
        WChar *pFileName = (WChar *)((char *)req + req->__header.buffer_off);
        wcscpy(pFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pFileName, wcsFileName);
        req->desiredAccess = ulDesiredAccess;
        req->shareMode = ulShareMode;
        req->creationDisposition = ulCreationDisposition;
        req->flagsAndAttributes = ulFlagsAndAttributes;
        req->hTemplateFile = hTemplateFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return reply->hFile;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return NULL;
}

Boolean IO_GetFileTime(
                PVoid hFile,
                PFILETIME pCreationTime,
                PFILETIME pLastAccessTime,
                PFILETIME pLastWriteTime)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(GetFileTime)
    {
        req->hFile = hFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            if (pCreationTime) {
                *pCreationTime = reply->CreationTime;
            }
            if (pLastAccessTime) {
                *pLastAccessTime = reply->LastAccessTime;
            }
            if (pLastWriteTime) {
                *pLastWriteTime = reply->LastWriteTime;
            }
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

UInt32 IO_SetFilePointer(
                PVoid hFile,
                Int32 lDistanceToMove,
                PInt32 pDistanceToMoveHigh,
                UInt32 ulMoveMethod)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert( WaitResult_OK == wr );

    SERVER_START_REQ(SetFilePointer)
    {
        req->hFile = hFile;
        req->DistanceToMove = lDistanceToMove;
//        req->DistanceToMoveHigh = *pDistanceToMoveHigh;
        req->MoveMethod = ulMoveMethod;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
//            if (pDistanceToMoveHigh) {
//                *pDistanceToMoveHigh = reply->DistanceToMoveHigh;
//            }
            g_IOBriageMutex.Unlock();
            return reply->DistanceToMove;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return IO_INVALID_SET_FILE_POINTER;
}

static UInt32 ReadFile(
                PVoid hFile,
                UInt32 ulNumOfBytesToRead)
{
    WaitResult wr;

    SERVER_START_REQ(ReadFile)
    {
        req->hFile = hFile;
        req->NumberOfBytesToRead = ulNumOfBytesToRead;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            return reply->NumberOfBytesRead;
        }
    }
    SERVER_END_REQ;
    return (UInt32)-1;
}

Boolean IO_ReadFile(
                PVoid hFile,
                PVoid pBuffer,
                UInt32 ulNumberOfBytesToRead,
                PUInt32 pNumberOfBytesRead)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert (WaitResult_OK == wr);

    UInt32 nTotalToRead = ulNumberOfBytesToRead;
    UInt32 nTotalRealRead = 0;
    UInt32 nPerRead = 0;
    void *pTemp = pBuffer;

    while (nTotalToRead) {
        nPerRead = 4096 < nTotalToRead ? 4096 : nTotalToRead;
        nPerRead = ReadFile(hFile, nPerRead);
        if (nPerRead == (UInt32)-1) {
            goto fail;
        }
        else if (nPerRead == 0) {
            break;
        }
        else {
            memcpy(pTemp, (void *)((char *)__VA(IOAddress) + 4096), nPerRead);
            pTemp = (void *)((char *)pTemp + nPerRead);
            nTotalToRead -= nPerRead;
            nTotalRealRead += nPerRead;
        }
    }
    *pNumberOfBytesRead = nTotalRealRead;
    g_IOBriageMutex.Unlock();
    return TRUE;

fail:
    g_IOBriageMutex.Unlock();
    return FALSE;
}

static UInt32 WriteFile(
                PVoid hFile,
                UInt32 ulNumOfBytesToWrite)
{
    WaitResult wr;

    SERVER_START_REQ(WriteFile)
    {
        req->hFile = hFile;
        req->NumberOFBytesToWrite = ulNumOfBytesToWrite;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            return reply->NumberOfBytesWritten;
        }
    }
    SERVER_END_REQ;
    return (UInt32)-1;
}

Boolean IO_WriteFile(
                PVoid hFile,
                const PVoid pBuffer,
                UInt32 ulNumberOfBytesToWrite,
                PUInt32 pNumberOfBytesWritten)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    UInt32 nTotalToWrite = ulNumberOfBytesToWrite;
    UInt32 nTotalRealWritten = 0;
    UInt32 nPerWrite= 0;
    void *pTemp = const_cast<void *>(pBuffer);

    while (nTotalToWrite) {
        nPerWrite = 4096 < nTotalToWrite ? 4096 : nTotalToWrite;
        memcpy(((char *)__VA(IOAddress) + 4096), pTemp, nPerWrite);
        nPerWrite = WriteFile(hFile,  nPerWrite);
        if (nPerWrite == (UInt32)-1) {
            goto fail;
        }
        else if (nPerWrite == 0) {  //the buffer is NULL
            break;
        }
        else {
            pTemp = (void *)((char *)pTemp + nPerWrite);
            nTotalToWrite -=  nPerWrite;
            nTotalRealWritten += nPerWrite;
        }
    }
    *pNumberOfBytesWritten = nTotalRealWritten;
    g_IOBriageMutex.Unlock();
    return TRUE;

fail:
    g_IOBriageMutex.Unlock();
    return FALSE;
}

UInt32 IO_GetFileSize(
                PVoid hFile,
                PUInt32 pFileSizeHigh)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(GetFileSize)
    {
        req->hFile = hFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
//            if (pFileSizeHigh) {
//                *pFileSizeHigh = reply->FileSizeHigh;
//            }
            g_IOBriageMutex.Unlock();
            return reply->FileSizeLow;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return IO_INVALID_FILE_SIZE;
}

Boolean IO_SetEndOfFile(
                PVoid hFile)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(SetEndOfFile)
    {
        req->hFile = hFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_GetDiskFreeSpace(
                WString wcsDirectoryName,
                PULARGE_INTEGER pFreeBytesAvailable,
                PULARGE_INTEGER pTotalNumberOfBytes,
                PULARGE_INTEGER pTotalNumberOfFreeBytes)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(GetDiskFreeSpace)
    {
        WChar *pDirectoryName = (WChar *)((char *)req + req->__header.buffer_off);

        if (NULL != wcsDirectoryName) {
            wcscpy(pDirectoryName, L".\\D\\");            //Add the real path prefix
            wcscat(pDirectoryName, wcsDirectoryName);
        }
        else {
            wcscpy(pDirectoryName, L".\\D\\");            //Add the real path prefix
        }
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            if (pFreeBytesAvailable) {
                *pFreeBytesAvailable = reply->FreeBytesAvailable;
            }
            if (pTotalNumberOfBytes) {
                *pTotalNumberOfBytes = reply->TotalNumberOfBytes;
            }
            if (pTotalNumberOfFreeBytes) {
                *pTotalNumberOfFreeBytes = reply->TotalNumberOfFreeBytes;
            }
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

PVoid IO_FindFirstFile(
                WString wcsFileName,
                PIO_FIND_DATA pFindFileData)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(FindFirstFile)
    {
        WChar *pFileName = (WChar *)((char *)req + (req->__header.buffer_off));
        wcscpy(pFileName, L".\\D\\");            //Add the real path prefix
        wcscat(pFileName, wcsFileName);
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            if (pFindFileData) {
                *pFindFileData = reply->FindFileData;
            }
            g_IOBriageMutex.Unlock();
            return reply->hFindFile;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return IO_INVALID_HANDLE_VALUE;
}

Boolean IO_FindNextFile(
                PVoid hFindFile,
                PIO_FIND_DATA pFindFileData)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(FindNextFile)
    {
        req->hFindFile = hFindFile;
        Outl(0x8D000004, IOAddress);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            if (pFindFileData) {
                *pFindFileData = reply->FindFileData;
            }
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_FindClose(
                PVoid hFindFile)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(FindClose)
    {
        req->hFindFile = hFindFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}

Boolean IO_CloseHandle(
                PVoid hFile)
{
    WaitResult wr;
    g_IOBriageMutex.Lock(&wr);
    assert(WaitResult_OK == wr);

    SERVER_START_REQ(CloseHandle)
    {
        req->hFile = hFile;
        Outl(0x8D000004, IOAddress);
        g_IOBriageEvent.Wait(&wr, NULL);
        if ((WaitResult_OK == wr) && (!reply->__header.errcode)) {
            g_IOBriageMutex.Unlock();
            return TRUE;
        }
    }
    SERVER_END_REQ;
    g_IOBriageMutex.Unlock();
    return FALSE;
}
